/**
 * Copyright (c) 2018-2023, NXOS Development Team
 * SPDX-License-Identifier: Apache-2.0
 * 
 * Contains: condition test 
 * 
 * Change Logs:
 * Date           Author            Notes
 * 2023-08-25     JasonHu           Init
 */

#include <base/condition.h>
#define NX_LOG_LEVEL NX_LOG_DBG
#include <base/log.h>
#include <test/integration.h>

#ifdef CONFIG_NX_TEST_INTEGRATION_CONDITION

#define PRODUCT_NR 5
#define WAIT_TIMES 15
NX_PRIVATE int productNumber;

NX_PRIVATE NX_Mutex mutex;
NX_PRIVATE NX_Condition condPush;
NX_PRIVATE NX_Condition condPop;

void ConsumerEntry1(void *arg)
{
    for (int i = 0 ; i < WAIT_TIMES ; ++i)
    {
        NX_MutexLock(&mutex);
        if (productNumber == 0) /* no product, wait */
        {
            NX_ConditionWait(&condPush, &mutex);
        }
        productNumber--;
        NX_LOG_D("consumer-%d: the productNumber is %d now", NX_ThreadSelf()->tid, productNumber);
        NX_ConditionSignal(&condPop);
        NX_MutexUnlock(&mutex);
    }
}

void ProducerEntry1(void *arg)
{
    for (int i = 0 ; i < WAIT_TIMES ; ++i)
    {
        NX_MutexLock(&mutex);
        if(productNumber == PRODUCT_NR){ /* product full, wait */
            NX_ConditionWait(&condPop, &mutex);
        }
        productNumber++;
        NX_LOG_D("producer-%d: the productNumber is %d now",NX_ThreadSelf()->tid,productNumber);
        NX_ConditionSignal(&condPush);
        NX_MutexUnlock(&mutex);
    }
}

void ProducerConsumerTest1(void)
{
    NX_MutexInit(&mutex);//初始化互斥量
    NX_ConditionInit(&condPush, 0);//初始化条件变量
    NX_ConditionInit(&condPop, 0);
    productNumber = 0;

    NX_Thread *thread1;
    NX_Thread *thread2;
    thread1 = NX_ThreadCreate("consumer", ConsumerEntry1, NX_NULL, NX_THREAD_PRIORITY_HIGH);
    NX_ThreadStart(thread1);
    thread2 = NX_ThreadCreate("producer", ProducerEntry1, NX_NULL, NX_THREAD_PRIORITY_HIGH);
    NX_ThreadStart(thread2);

    NX_ThreadWait(thread1, NX_NULL);
    NX_ThreadWait(thread2, NX_NULL);

    NX_LOG_D("\nthe productNumber finally is %d\n",productNumber);
}

void ConsumerEntry2(void *arg)
{    
    for (int i = 0 ; i < WAIT_TIMES ; ++i)
    {
        NX_MutexLock(&mutex);
        while (productNumber == 0){
            NX_ConditionWait(&condPush, &mutex);
        }
        productNumber--;
        NX_LOG_D("consumer-%d: the productNumber is %d now", NX_ThreadSelf()->tid, productNumber);
        NX_ConditionSignal(&condPop);
        NX_MutexUnlock(&mutex);
    }
}

void ProducerEntry2(void*arg)
{
    for (int i = 0 ; i < WAIT_TIMES ; ++i)
    {
        NX_MutexLock(&mutex);
        while (productNumber == PRODUCT_NR)
        {
            NX_ConditionWait(&condPop, &mutex);
        }
        productNumber++;
        NX_LOG_D("producer-%d: the productNumber is %d now",NX_ThreadSelf()->tid, productNumber);
        NX_ConditionSignal(&condPush);
        NX_MutexUnlock(&mutex);
    }
}

void ProducerConsumerTest2(void)
{
    NX_MutexInit(&mutex);//初始化互斥量
    NX_ConditionInit(&condPush, 0);//初始化条件变量
    NX_ConditionInit(&condPop, 0);
    productNumber = 0;
    
    NX_Thread *producerThread[20];
    NX_Thread *consumerThread[20];
    
    for(int i = 0 ; i < 20 ; ++i){//创建20个消费者线程
        consumerThread[i] = NX_ThreadCreate("consumer", ConsumerEntry2, NX_NULL, NX_THREAD_PRIORITY_HIGH);
        NX_ThreadStart(consumerThread[i]);
    }
    for(int i = 0 ; i < 20 ; ++i){//创建20个生产者线程
        producerThread[i] = NX_ThreadCreate("producer", ProducerEntry2, NX_NULL, NX_THREAD_PRIORITY_HIGH);
        NX_ThreadStart(producerThread[i]);
    }

    for(int i = 0 ; i < 20 ; ++i){//创建20个生产者线程
        NX_ThreadWait(consumerThread[i], NX_NULL);
        NX_ThreadWait(producerThread[i], NX_NULL);
    }

    NX_LOG_D("\nthe productNumber finally is %d\n", productNumber);
}

NX_INTEGRATION_TEST(NX_ConditionTest)
{
    ProducerConsumerTest1();
    ProducerConsumerTest2();
    return NX_EOK;
}

#endif
